package com.kullachi.jmx.d3;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.media.j3d.Alpha;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Material;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.image.TextureLoader;

/**
 * @author Sundar
 *
 */
public class MBean3D extends BranchGroup implements NotificationListener{
	
	Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    TransformGroup objTrans;
    Transform3D    transForm3d;
    
    List<MBeanAttributeInfo3D> attributes = new ArrayList<MBeanAttributeInfo3D>();
    List<MBeanOperationInfo3D> operations = new ArrayList<MBeanOperationInfo3D>();
    
    
    public MBean3D(Transform3D transform,ObjectName bean){
    	this(transform,null,bean);
    }
    
	public MBean3D(Transform3D transform,Texture texture,ObjectName bean){
		this(true,false,transform,texture,bean);
	}
	
	/**
	 * @param isSpning
	 * @param isSheled
	 */
	public MBean3D(boolean isSpning,boolean isSheled,Transform3D transform,Texture texture,ObjectName bean){
		this.transForm3d = transform;
		 BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0,
					0.0), 100.0);
		 
		
		Appearance 	app 		= new Appearance();
		Color3f 	objColor 	= new Color3f(Color.DARK_GRAY);
	    app.setMaterial(new Material(objColor, black, objColor, white, 80.0f));
	    
		//Shiled text
	    if(texture !=null){
		    app.setTexture(texture);
		    TextureAttributes texAttr = new TextureAttributes();
		    texAttr.setTextureMode(TextureAttributes.MODULATE);
		    app.setTextureAttributes(texAttr);
	    } else {
			// Create name base image
			BufferedImage image = new BufferedImage(100, 100,
					BufferedImage.TYPE_INT_RGB);
			Graphics g = image.getGraphics();

			// create a rectangle filled with the color white:
			g.setColor(Color.DARK_GRAY);
			g.fillRect(0, 0, 100, 100);

			// add some text
			g.setColor(Color.BLUE);
			g.drawString(bean.getKeyProperty("name"), 30, 50);
			app.setTexture(new TextureLoader(image).getTexture());
		}
		    ///
	    if(!isSheled){
	    	TransparencyAttributes arg0 = new TransparencyAttributes();
	    	arg0.setTransparency(0.1f);
	    	arg0.setTransparencyMode(TransparencyAttributes.SCREEN_DOOR);
			app.setTransparencyAttributes(arg0);
	    }
	    
	    Sphere 		sphere 		= new Sphere(1.0f, Sphere.GENERATE_NORMALS
		          | Sphere.GENERATE_TEXTURE_COORDS,app);
		
	    // create transfrmer
	    objTrans = new TransformGroup(transform);
	    
	    TransformGroup spinTg = new TransformGroup();
	    spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	    spinTg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	    spinTg.addChild(sphere);
	   
	    
	    // Self spin
	    if (isSpning) {
			Transform3D yAxis = new Transform3D();
			yAxis.setTranslation(new Vector3f(0.0f, 0.0f, 0.0f));
			Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE, 0, 0,
					5000, 0, 0, 0, 0, 0);
			RotationInterpolator rotator = new RotationInterpolator(
					rotationAlpha, spinTg, yAxis, 0.0f, (float) Math.PI * 2.0f);
			rotator.setSchedulingBounds(bounds);
			// Add the behavior and the transform group to the object
			objTrans.addChild(rotator);
		}
	    
	    // Add environment color
	    Color3f alColor = new Color3f(Color.WHITE);
        AmbientLight aLgt = new AmbientLight(alColor);
        aLgt.setInfluencingBounds(bounds);
        this.addChild(aLgt);
        
	    objTrans.addChild(spinTg);
		this.addChild(objTrans);
		
	}

	public void addAttribute(MBeanAttributeInfo3D beanAttributeInfo3D, Object value) {
		Transform3D 	t 		= new Transform3D(transForm3d);
		Vector3d v= new Vector3d(0.0, 0.0, 0.0);
		transForm3d.get(v);
		
		switch(attributes.size()){
		case 0:
			t.set(0.01,new Vector3d(v.x+0.12,v.y,v.z));
			break;
		case 1:
			t.set(0.01,new Vector3d(v.x-0.12,v.y,v.z));	
			break;
		case 2:
			t.set(0.01,new Vector3d(v.x,v.y+0.12,v.z));	
			break;
		case 3:
			t.set(0.01,new Vector3d(v.x,v.y-0.12,v.z));	
			break;
		}
		this.addChild(beanAttributeInfo3D.getViewer(t,value));
		
		attributes.add(beanAttributeInfo3D);
	}

	public void addOperation(MBeanOperationInfo3D beanOperationInfo3D) {
		Transform3D 	t 		= new Transform3D(transForm3d);
		Vector3d v= new Vector3d(0.0, 0.0, 0.0);
		transForm3d.get(v);
		
		switch(operations.size()){
		case 0:
			t.set(0.01,new Vector3d(v.x+0.10,v.y + 0.05,v.z));
			break;
		case 1:
			t.set(0.01,new Vector3d(v.x-0.10,v.y + 0.05,v.z));	
			break;
		case 2:
			t.set(0.01,new Vector3d(v.x + 0.05,v.y+0.10,v.z));	
			break;
		case 3:
			t.set(0.01,new Vector3d(v.x + 0.05,v.y-0.10,v.z));	
			break;
		case 4:
			t.set(0.01,new Vector3d(v.x+0.10,v.y ,v.z));
			break;
		case 5:
			t.set(0.01,new Vector3d(v.x-0.10,v.y ,v.z));	
			break;
		case 6:
			t.set(0.01,new Vector3d(v.x ,v.y+0.10,v.z));	
			break;
		case 7:
			t.set(0.01,new Vector3d(v.x ,v.y-0.10,v.z));	
			break;	
			
		case 8:
			t.set(0.01,new Vector3d(v.x + 0.07,v.y+0.10,v.z));	
			break;
		case 9:
			t.set(0.01,new Vector3d(v.x + 0.07,v.y-0.10,v.z));	
			break;		
		}
		this.addChild(beanOperationInfo3D.getViewer(t));
		operations.add(beanOperationInfo3D);
	}

	@Override
	public void handleNotification(Notification notification, Object handback) {
		operations.get(0).error();
		
	}
}
